<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>大屏渲染</title>
    <link rel="stylesheet" href="../static/layui/css/layui.css">
    <link rel="stylesheet" href="./index.css">
    <style>
        body {
            -moz-user-select: none;
            -webkit-user-select: none;
            -ms-user-select: none;
            user-select: none;
        }

        .context-menu {
            position: absolute;
            background-color: white;
            border: 1px solid #ccc;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
            z-index: 1000;
        }

        .context-menu-item {
            padding: 8px 12px;
            cursor: pointer;
        }

        .context-menu-item:hover {
            background-color: #eee;
        }
    </style>

    <script type="importmap">
    {
        "imports": {
        "three": "../three/v170/three.module.min.js",
        "three/addons/": "../three/v170/"
        }
    }
    </script>
</head>

<body>
    <div class="screen-wrapper">
        <!-- 中间threejs的渲染区域 -->
        <div class="three-box" id="three-box"></div>

        <!-- 标签信息 -->
        <div id="scene-container"></div>
        <div id="labels"></div>

        <div style="position: fixed;left: 0;top: 0;z-index: 9999;display: none;">
            <button id="x_increase">x_增加</button>
            <button id="x_decrease">x_减少</button>
            <button id="y_increase">y_增加</button>
            <button id="y_decrease">y_减少</button>
        </div>

        <div style="position: fixed;left: 0;top: 0;z-index: 9999;">
            <div id="reset_btn">还原</div>
            <div id="add_advice_btn">添加设备</div>
        </div>

        <script src="../static/js/echarts.min-5.5.1.js"></script>
        <script src="../static/layui/layui.js"></script>
        <script type="module">
            import * as THREE from 'three';
            import { CSS2DRenderer, CSS2DObject } from "three/addons/renderers/CSS2DRenderer.js";
            import { CSS3DRenderer, CSS3DObject, CSS3DSprite } from "three/addons/renderers/CSS3DRenderer.js";
            import { TrackballControls } from 'three/addons/controls/TrackballControls.js';
            import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
            import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
            import { DragControls } from 'three/addons/controls/DragControls.js';
            import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

            layui.use(function () {
                var layer = layui.layer;
                var util = layui.util;
                console.log(`bigScreen.html 118 [layer]`, layer);

                let scene, camera, renderer, controls, isPaused;
                let labelRenderer = null;
                let middle_shebei = {};// 设备--用于位置
                let middle_dengguang = null;// 灯光--射光灯
                const cur_ratio = 0.02;// 缩小的系数
                const raycaster = new THREE.Raycaster();
                const mouse = new THREE.Vector2();
                const texturedPlanes = [];
                let labelsArr = [];// 标签数组
                let renderOrder = 1;// 渲染顺序
                const planeCache = {};// 设备平面缓存

                // 背景数组
                let bgcArr = [
                    {
                        devicesID: 'bgc_1',// 设备1
                        imgURL: './images/souce_05.png',
                        width: 1393,
                        height: 972,
                        label_offset: [0, 0, 0],// 机台偏移量
                    },
                    {
                        devicesID: 'bgc_2',// 设备2
                        imgURL: './images/souce_02.png',
                        width: 715,
                        height: 644,
                        label_offset: [0, 0, 0],// 机台偏移量
                    }
                ];
                // 设备数组
                let devicesArr = [
                    {
                        devicesID: 'machine_1',// 设备1
                        imgURL: './images/souce_01.png',
                        width: 107,
                        height: 96,
                        label_offset: [0.0666999899999869, 0.7156000099999965, 0],// 机台偏移量
                    },
                    {
                        devicesID: 'machine_2',// 设备2
                        imgURL: './images/souce_03.png',
                        width: 111,
                        height: 102,
                        label_offset: [-0.3499999999999993, 0.2499999999999988, 0],// 机台偏移量
                    }
                ];

                // 生成平面
                function createPlane(obj) {
                    let imgURL = '';
                    let cur_width = 0;
                    let cur_height = 0;
                    if (obj.devicesID.startsWith('bgc')) {
                        const findIndex = bgcArr.findIndex(item => item.devicesID === obj.devicesID);
                        imgURL = bgcArr[findIndex].imgURL;
                        cur_width = bgcArr[findIndex].width;
                        cur_height = bgcArr[findIndex].height;
                    } else if (obj.devicesID.startsWith('machine')) {
                        const findIndex = devicesArr.findIndex(item => item.devicesID === obj.devicesID);
                        imgURL = devicesArr[findIndex].imgURL;
                        cur_width = devicesArr[findIndex].width;
                        cur_height = devicesArr[findIndex].height;
                    }
                    const textureLoader = new THREE.TextureLoader();
                    const texture = textureLoader.load(imgURL);
                    texture.anisotropy = renderer.capabilities.getMaxAnisotropy();
                    texture.minFilter = THREE.LinearMipmapLinearFilter;// LinearFilter
                    texture.magFilter = THREE.LinearFilter;
                    texture.generateMipmaps = true;
                    texture.wrapS = texture.wrapT = THREE.ClampToEdgeWrapping;

                    const geometry = new THREE.PlaneGeometry(cur_width * cur_ratio, cur_height * cur_ratio); // 根据图片比例设置平面尺寸

                    const material = new THREE.MeshBasicMaterial({
                        map: texture,
                        transparent: true, // 允许透明
                        opacity: 1, // 设置不透明度（0.0为完全透明，1.0为完全不透明）
                        side: THREE.DoubleSide, // 设置材质为双面
                        blending: THREE.NormalBlending, // 使用正常混合模式
                        // depthTest: false, // 禁用深度测试
                        // depthWrite: false // 禁止写入深度缓冲
                        // metalness: 0, // 设置金属度为 0.5
                        // alphaTest: 0.1,// 透明度阈值
                        // color: 0xffffff, // 设置材质颜色
                    });
                    material.map.colorSpace = THREE.SRGBColorSpace;

                    const plane = new THREE.Mesh(geometry, material);
                    plane.material.depthWrite = false;// 该平面在渲染时会写入深度缓冲区
                    const p_x = (obj.position || [])[0] || 0;
                    const p_y = (obj.position || [])[1] || 0;
                    const p_z = (obj.position || [])[2] || 0;
                    plane.position.set(p_x, p_y, p_z);
                    // plane.renderOrder = obj.renderOrder || 0; // 设置渲染顺序
                    plane.renderOrder = renderOrder; // 设置渲染顺序
                    plane.userData = obj;
                    renderOrder++;
                    scene.add(plane);
                    return plane;
                }

                // 添加纹理的函数
                function addTexturedPlane(obj) {
                    const plane = createPlane(obj);
                    if (obj.labelObj) {
                        createLabel({ plane: plane, ...obj });
                    }
                }

                function createLabel(obj) {
                    // object.geometry.computeBoundingBox(); // 计算包围盒
                    const labelObj = obj.labelObj;
                    const findIndex = devicesArr.findIndex(item => item.devicesID === obj.devicesID);
                    const label_offset = devicesArr[findIndex].label_offset;// 获取偏移量

                    const labelDiv = document.createElement('div');
                    labelDiv.className = 'label-wrapper';
                    labelDiv.innerHTML = `
                <div class="label-bottom"></div>
                <div class="label-line-1"></div>
                <div class="label-line-2"></div>
                <div class="label-content">
                    <h3 class="label-name">${labelObj.name}</h3>
                    <div class="label-item">进程1:xxxx</div>
                    <div class="label-item">进程2:xxxx</div>
                    <div class="label-item">进程3:xxxx</div>
                    <div class="label-item">进程4:xxxx</div>
                </div>
            `;
                    document.getElementById('scene-container').appendChild(labelDiv);
                    const labelObject = new CSS3DObject(labelDiv);

                    const p_x = (obj.position || [])[0] + label_offset[0];
                    const p_y = (obj.position || [])[1] + label_offset[1];
                    const p_z = (obj.position || [])[2] + label_offset[2];
                    labelObject.position.set(p_x, p_y, p_z);
                    labelObject.scale.set(cur_ratio, cur_ratio, cur_ratio);
                    labelObject.userData = obj;
                    middle_shebei['label_' + labelObj.name] = labelObject;
                    scene.add(labelObject);

                    // 检查labelsArr是否存
                    // const find_index = labelsArr.findIndex(item => item.obj.labelObj.uuid === labelObj.uuid);
                    // if (find_index === -1) {
                    //     labelsArr.push({
                    //         labelObject: labelObject,
                    //         plane: obj.plane,
                    //         obj: obj,
                    //     })
                    // } else {
                    //     labelsArr[find_index] = {
                    //         labelObject: labelObject,
                    //         plane: obj.plane,
                    //         obj: obj,
                    //     }
                    // }
                }

                function init() {
                    scene = new THREE.Scene();
                    camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
                    camera.rotation.set(0, 0, 0);
                    // camera.position.set(10, 10, 10);
                    camera.position.set(0, 0, 15);// 正视图
                    // camera.lookAt(new THREE.Vector3(0, 0, 0));

                    // 创建渲染器
                    renderer = new THREE.WebGLRenderer({
                        antialias: true,//
                        alpha: true,// 设置背景透明
                        physicallyCorrectLights: true,// 开启物理光照
                        logarithmicDepthBuffer: true,// 开启深度缓存
                        powerPreference: "high-performance",// 
                    });
                    renderer.setSize(window.innerWidth, window.innerHeight);
                    renderer.setPixelRatio(window.devicePixelRatio);
                    document.getElementById('three-box').appendChild(renderer.domElement);

                    // var axesHelper = new THREE.AxesHelper(1000);
                    // scene.add(axesHelper);// 创建坐标轴辅助对象

                    controls = new OrbitControls(camera, renderer.domElement);// 添加控制器
                    controls.enablePan = true;// 添加平移功能

                    const ambientLight = new THREE.AmbientLight(0xffffff, 1);
                    scene.add(ambientLight);// 添加环境光

                    const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
                    directionalLight.position.set(15, 15, 0);// 设置光源位置
                    scene.add(directionalLight);// 添加平行光

                    labelRenderer = new CSS3DRenderer();
                    labelRenderer.setSize(window.innerWidth, window.innerHeight);
                    labelRenderer.domElement.style.position = 'absolute';
                    labelRenderer.domElement.style.top = 0;
                    labelRenderer.domElement.style.left = 0;
                    labelRenderer.domElement.style.zIndex = 3;
                    // 不遮挡canvas和threejs的点击事件;导致使用CSS2DObject添加的HTML标签点击事件无效;
                    labelRenderer.domElement.style.pointerEvents = 'none';
                    document.body.appendChild(labelRenderer.domElement);

                    // 添加场景背景图
                    addTexturedPlane({
                        devicesID: 'bgc_1',
                        position: [0, 0, 0],
                    })
                    addTexturedPlane({
                        devicesID: 'machine_1',
                        position: [-10.7, -2.4, 0],
                        labelObj: {
                            uuid: '1',
                            name: '1号机台',
                        },
                    })
                    addTexturedPlane({
                        devicesID: 'machine_1',
                        position: [-8.8, -3.4, 0],
                        labelObj: {
                            uuid: '2',
                            name: '2号机台',
                        },
                    })
                    addTexturedPlane({
                        devicesID: 'machine_2',
                        position: [-3.6, -6.49, 0],
                        labelObj: {
                            uuid: '3',
                            name: '3号机台',
                        },
                    })
                    addTexturedPlane({
                        devicesID: 'machine_2',
                        position: [0.908999, -2.3, 0],
                        labelObj: {
                            uuid: '4',
                            name: '4号机台',
                        },
                    })
                    addTexturedPlane({
                        devicesID: 'machine_2',
                        position: [-1.199999, -0.01222, 0],
                        labelObj: {
                            uuid: '5',
                            name: '5号机台',
                        },
                    })
                    addTexturedPlane({
                        devicesID: 'machine_2',
                        position: [1.95999, 1.59999, 0],
                        labelObj: {
                            uuid: '6',
                            name: '6号机台',
                        },
                    })
                    addTexturedPlane({
                        devicesID: 'machine_2',
                        position: [6.2999, -0.2000999, 0],
                        labelObj: {
                            uuid: '7',
                            name: '7号机台',
                        },
                    })

                    addTexturedPlane({
                        devicesID: 'machine_2',
                        position: [8.4998, -1.400099, 0],
                        labelObj: {
                            uuid: '8',
                            name: '8号机台',
                        },
                    })

                    // 窗口调整
                    window.addEventListener('resize', () => {
                        camera.aspect = window.innerWidth / window.innerHeight;
                        camera.updateProjectionMatrix();
                        renderer.setSize(window.innerWidth, window.innerHeight);
                        labelRenderer.setSize(window.innerWidth, window.innerHeight);
                    });


                    window.addEventListener('contextmenu', onContextMenu, false);
                    window.addEventListener('dblclick', onDoubleClick, false);
                    window.addEventListener('click', hideContextMenu, false);

                    // 添加键盘事件监听器
                    document.addEventListener('keydown', function (event) {
                        if (event.keyCode === 38) { controls.target.y += 1; }
                        else if (event.keyCode === 40) { controls.target.y -= 1; }
                        else if (event.keyCode === 37) { controls.target.x -= 1; }
                        else if (event.keyCode === 39) { controls.target.x += 1; }
                        controls.update();
                    });

                    loop();

                    setTimeout(() => {
                        addGUI();// 添加GUI
                    }, 1000)
                }

                function addGUI() {
                    // 创建 GUI，设置gui面板的标题
                    // const gui = new GUI({ 'title': "操作区" });
                    // const obj = {
                    //     color: '#ff0000',
                    //     speed: 2.5,
                    //     isVisible: true,
                    //     selectedOptions: ['苹果🍎']
                    // };

                    // gui.addColor(obj, 'color').onChange((value) => {
                    //     sphereMa.color.set(value);
                    // });

                    // const sphereFol = gui.addFolder('机台位置');
                    // console.log(`bigScreen.html 410 [middle_shebei['1号机台']]`, middle_shebei['1号机台']);
                    // sphereFol.add(middle_shebei['2号机台'].position, 'x', -20, 20, 0.1)
                    // sphereFol.add(middle_shebei['2号机台'].position, 'y', -20, 20, 0.1)

                    // const sphereFol_2 = gui.addFolder('悬浮窗');
                    // sphereFol_2.add(middle_shebei['2号机台'].position, 'x', -20, 20, 0.1).onChange(function (value) {
                    //     updateLabelPosition(middle_shebei['2号机台'], [value, middle_shebei['2号机台'].position.y, middle_shebei['2号机台'].position.z]);
                    // });
                    // sphereFol_2.add(middle_shebei['2号机台'].position, 'y', -20, 20, 0.1).onChange(function (value) {
                    //     updateLabelPosition(middle_shebei['2号机台'], [middle_shebei['2号机台'].position.x, value, middle_shebei['2号机台'].position.z]);
                    // });


                    // const cameraFol = gui.addFolder('相机')
                    // cameraFol.add(camera.position, 'x', -5, 8, 0.1)
                    // cameraFol.add(camera.position, 'y', -5, 8, 0.1)
                    // cameraFol.add(camera.position, 'z', -5, 8, 0.1)

                    // const lightFol = gui.addFolder('灯光')
                    // lightFol.add(light.position, 'x', -5, 5, 0.1)
                    // lightFol.add(light.position, 'y', -5, 5, 0.1)
                    // lightFol.add(light.position, 'z', -5, 5, 0.1)
                }

                // 更新标签位置函数
                function updateLabelPositions() {
                    labelsArr.forEach(obj => {
                        const vector = new THREE.Vector3();
                        obj.plane.getWorldPosition(vector);
                        if (obj.labelObject) {
                            obj.labelObject.position.copy(vector);
                            obj.labelObject.lookAt(camera.position);
                        }
                    });
                }

                var skip;
                function loop() {
                    skip++;
                    requestAnimationFrame(loop);
                    if (skip < 4) {
                        return;
                    } else {
                        skip = 0;
                    }

                    // updateLabelPositions();// 更新标签位置
                    controls.update(); // 更新控制器
                    renderer.render(scene, camera); // 渲染场景
                    labelRenderer.render(scene, camera); // 渲染标签
                }

                init();

                // 获取按钮元素
                const x_increase = document.getElementById('x_increase');
                const x_decrease = document.getElementById('x_decrease');
                const y_increase = document.getElementById('y_increase');
                const y_decrease = document.getElementById('y_decrease');

                const cur_jitai = '3号机台';
                const selectdevice = 'label_' + cur_jitai;
                function con_position() {
                    console.log(`bigScreen.html 543 [middle_shebei]`, middle_shebei);
                    console.log(selectdevice, [middle_shebei[selectdevice].position.x, middle_shebei[selectdevice].position.y])
                }
                x_increase.addEventListener('click', (e) => {
                    e.preventDefault(); // 防止默认行为
                    e.stopPropagation(); // 阻止事件冒泡到全局监听器
                    middle_shebei[selectdevice].position.x += 0.05;
                    con_position();
                });
                x_decrease.addEventListener('click', (e) => {
                    e.preventDefault(); // 防止默认行为
                    e.stopPropagation(); // 阻止事件冒泡到全局监听器
                    middle_shebei[selectdevice].position.x -= 0.05;
                    con_position();
                });
                y_increase.addEventListener('click', (e) => {
                    e.preventDefault(); // 防止默认行为
                    e.stopPropagation(); // 阻止事件冒泡到全局监听器
                    middle_shebei[selectdevice].position.y += 0.05;
                    con_position();
                });
                y_decrease.addEventListener('click', (e) => {
                    e.preventDefault(); // 防止默认行为
                    e.stopPropagation(); // 阻止事件冒泡到全局监听器
                    middle_shebei[selectdevice].position.y -= 0.05;
                    con_position();
                });

                // 还原 初始化的场景
                const reset_btn = document.getElementById('reset_btn');
                reset_btn.addEventListener('click', () => {
                    controls.reset();
                    controls.update(); // 更新控制器
                    renderer.render(scene, camera); // 渲染场景
                    labelRenderer.render(scene, camera); // 渲染标签
                });

                function onContextMenu(event) {
                    event.preventDefault();
                    handleMouseEvent(event, showContextMenu);
                }

                function onDoubleClick(event) {
                    event.preventDefault();
                    handleMouseEvent(event, showContextMenu);
                }

                function handleMouseEvent(event, callback) {
                    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
                    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

                    raycaster.setFromCamera(mouse, camera);
                    const intersects = raycaster.intersectObjects(scene.children);

                    if (intersects.length > 0) {
                        // 简单一点：只检测第一个是设备而不是背景的设备(暂不考虑重叠的设备)
                        for (let i = 0; i < intersects.length; i++) {
                            const intersectedObject = intersects[i].object;
                            const devicesID = intersectedObject.userData.devicesID || null;
                            if (intersectedObject.userData && ['machine_1', 'machine_2'].includes(devicesID)) {
                                callback(event, intersectedObject.userData);
                                console.log(`bigScreen.html 586 [已响应双击事件]`,);
                                break;
                            }
                        }
                    }
                }

                function showContextMenu(event, userData) {
                    hideContextMenu();

                    const menu = document.createElement('div');
                    menu.className = 'context-menu';
                    menu.style.top = `${event.clientY}px`;
                    menu.style.left = `${event.clientX}px`;

                    console.log(`bigScreen.html 651 [userData.devicesID]`, userData.devicesID);
                    if (['machine_1', 'machine_2'].includes(userData.devicesID)) {
                        console.log(`bigScreen.html 621 [userData]`, userData);
                        const editOption = document.createElement('div');
                        editOption.className = 'context-menu-item';
                        editOption.innerText = '编辑';
                        editOption.onclick = function () {
                            editPlane(userData);
                        };
                        menu.appendChild(editOption);

                        const deleteOption = document.createElement('div');
                        deleteOption.className = 'context-menu-item';
                        deleteOption.innerText = '删除';
                        deleteOption.onclick = function () {
                            deletePlane(userData);
                        };
                        menu.appendChild(deleteOption);

                        document.body.appendChild(menu);
                        console.log('添加过了呀');
                    } else {
                        hideContextMenu();
                        console.log('没有响应到');
                    }
                }

                function hideContextMenu() {
                    const menus = document.querySelectorAll('.context-menu');
                    menus.forEach(menu => menu.remove());
                }

                function editPlane(userData) {
                    console.log('Editing plane:', userData);
                }

                function deletePlane(userData) {
                    const objectsToRemove = [];
                    scene.traverse(function (child) {
                        const cur_data = child.userData || {};
                        const labelObj = cur_data.labelObj || {};

                        if (child instanceof THREE.Mesh) {
                            if (labelObj.uuid === userData.labelObj.uuid) {
                                objectsToRemove.push(child);
                            }
                        } else if (['Object3D', 'CSS3DObject', 'CSS3DSprite'].includes(child.type)) {
                            // child instanceof THREE.Object3D
                            if (labelObj.uuid === userData.labelObj.uuid) {
                                objectsToRemove.push(child);
                            }
                        }
                    });
                    objectsToRemove.forEach(obj => scene.remove(obj));
                }
            })
        </script>
</body>

</htm>